package com.xjscrm.console.chat.core;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.uzai.trace.TraceGenerate;
import com.xjscrm.common.constant.CacheKey;
import com.xjscrm.common.exception.BusinessException;
import com.xjscrm.console.chat.cache.CacheHolder;
import com.xjscrm.console.chat.enums.ChatMsgType;
import com.xjscrm.console.chat.frame.recv.RBaseMsg;
import com.xjscrm.console.chat.frame.send.SResultMsg;
import com.xjscrm.console.chat.utils.JsonUtils;
import com.xjscrm.console.chat.utils.MessageUtil;
import com.xjscrm.console.vo.LoginVO;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Map;
import java.util.Objects;

/**
 * @author mingyang.chen create in 2024/3/11 18:30
 */
@Slf4j
public abstract class ChatBaseMsgHandler<T extends RBaseMsg> implements ChatMsgHandler {

    @Autowired
    private CacheHolder cacheHolder;

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Override
    @TraceGenerate
    public void handle(ChannelHandlerContext ctx, String msg) {
        T contentObj = JSON.parseObject(msg, msgClass());
        try {
            String token = contentObj.getToken();
            if (StringUtils.isBlank(token)) {
                MessageUtil.sendMsg(ctx.channel(), SResultMsg.fail(contentObj, "未认证, 请携带令牌", ChatMsgType.s_401));
                return;
            }

            String cacheKey = String.format(CacheKey.AUTH_TOKEN, token);
            Map<Object, Object> loginInfoMap = redisTemplate.opsForHash().entries(cacheKey);
            if (ObjectUtils.isEmpty(loginInfoMap)) {
                MessageUtil.sendMsg(ctx.channel(), SResultMsg.fail(contentObj, "未认证, 令牌已失效", ChatMsgType.s_401));
                return;
            }
            LoginVO loginInfo = new LoginVO();
            BeanUtil.fillBeanWithMap(loginInfoMap, loginInfo, true);

            contentObj.setStaffId(loginInfo.getId());
            contentObj.setMerId(loginInfo.getMerId());

            if (this.checkMsg(contentObj)) {
                log.info("消息检查未通过: {}", msg);
                MessageUtil.sendMsg(ctx.channel(), SResultMsg.fail(contentObj, "消息参数非法"));
                return;
            }
            if (!basic()) {
                Channel staffChannel = cacheHolder.getStaffChannel(contentObj.getStaffId());
                if (Objects.isNull(staffChannel)) {
                    throw new BusinessException("员工未上班, 请上班后操作");
                }
            }
            //
            if (!canOpt(contentObj)) {
                throw new BusinessException("不允许的操作");
            }

            SResultMsg sResultMsg = this.doHandle(contentObj, ctx);
            ctx.writeAndFlush(new TextWebSocketFrame(JsonUtils.toJson(sResultMsg)));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            SResultMsg fail = SResultMsg.fail(contentObj, e.getMessage());
            ctx.writeAndFlush(new TextWebSocketFrame(JsonUtils.toJson(fail)));
        }
    }

    public boolean basic() {
        return false;
    }

    public boolean canOpt(T obj) {
        return true;
    }

    public boolean checkMsg(T baseMsg) {
        Integer msgType = baseMsg.getMsgType();
        ChatMsgType byCode = ChatMsgType.getByCode(msgType);
        if (Objects.isNull(byCode)) {
            throw new BusinessException("消息类型暂不支持");
        }
        return !ObjectUtils.allNotNull(baseMsg.getMerId(), baseMsg.getMsgType(), baseMsg.getReqId(), baseMsg.getStaffId());
    }

    public abstract Class<T> msgClass();

    /**
     * 具体操作
     */
    public abstract SResultMsg doHandle(T content, ChannelHandlerContext ctx);
}
